package com.cenxi.ipdemo1.controller.excel;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.alibaba.fastjson2.JSON;
import com.cenxi.ipdemo1.domain.AttendanceCheckInRecord;
import com.cenxi.ipdemo1.utils.LocalDateUtil;
import com.cenxi.ipdemo1.utils.RedisCache;
import com.cenxi.ipdemo1.utils.excel.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@RequestMapping("/excel")
@RestController
@Slf4j
public class ExcelController {
    @Autowired
    private RedisCache redisCache;

    @GetMapping("/exportExcel")
    public void exportExcel(HttpServletResponse response) throws Exception {
        export(response);
    }

    @PostMapping("/importExcel")
    public void importExcel(@RequestParam("file") MultipartFile file) throws Exception {
        importExcels(file);
    }


    private void importExcels(MultipartFile file) {
        ExcelListener memberExcelListener = new ExcelListener(redisCache);
        try {
            EasyExcelFactory.read(file.getInputStream(),
                    memberExcelListener).sheet().doRead();
        } catch (IOException e) {
            log.error("应用导入读取错误");
        }
    }

    private void export(HttpServletResponse response) throws Exception  {
        HttpUtils.setResponse(response, URLEncoder.encode("应用导出" + "-" + System.currentTimeMillis() + ".xlsx", "UTF-8"));
        List<Integer> countList = new ArrayList<>();
        List<Integer> randomCountList = new ArrayList<>();
        List<Integer> fontColor = new ArrayList<>();
        List<List<String>> data = getData(countList, randomCountList, fontColor);

        // 设置单元格背景颜色
        Map<Integer, List<Integer>> lackCard = new HashMap<>();
        Random r = new Random();
        for (Integer i : randomCountList) {
            lackCard.put(i, Collections.singletonList(r.nextInt(getRow().get(0).size() - 1)));
        }

        // 合并单元格
        List<CellRangeAddress> cellRangeAddresssList = new ArrayList<>();
        //表头合并
        cellRangeAddresssList.add(new CellRangeAddress(0, 4, 0, getRow().get(1).size() - 1));
        cellRangeAddresssList.add(new CellRangeAddress(5, 5, 0, getRow().get(1).size() - 1));

        // 设置流程颜色
        Map<Integer, List<Integer>> lackCard1 = new HashMap<>();
        List<String> strings = getRow().get(0);
        List<Integer> cl = new ArrayList<>();
        Collections.addAll(cl, strings.size() + 1, strings.size() + 2, strings.size() + 3, strings.size() + 4, strings.size() + 5, strings.size() + 6, strings.size() + 7, strings.size() + 8, strings.size() + 9, strings.size() + 10, strings.size() + 11, strings.size() + 12, strings.size() + 13, strings.size() + 14, strings.size() + 15, strings.size() + 16, strings.size() + 17);
        for (Integer count : countList) {
            lackCard1.put(count, cl);
        }

        // 设置字体颜色
        Map<Integer, List<Integer>> fontColorMap = new HashMap<>();
        for (Integer count : fontColor) {
            List<Integer> colors = new ArrayList<>();
            for (int i = 0; i < strings.size(); i++) {
                colors.add(i);
            }
            fontColorMap.put(count, colors);
        }

        EasyExcelFactory.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLSX)
                .head(getHead())
                .registerWriteHandler(new SimpleColumnWidthStyleStrategy(6))
                .registerWriteHandler(new CustomHeadStyleStrategy())
                .registerWriteHandler(new CustomMergeStrategy(cellRangeAddresssList))
                .registerWriteHandler(new CustomColorStyleStrategy(lackCard, lackCard1, fontColorMap, data.size() - 1))
                .sheet("应用导出")
                .doWrite(data);
    }

    private List<List<String>> getData(List<Integer> countList, List<Integer> randomCountList, List<Integer> fontColor) {
        String cacheObject = redisCache.getCacheObject("1200:punch");
        List<AttendanceCheckInRecord> parse = JSON.parseArray(cacheObject, AttendanceCheckInRecord.class);
        List<List<String>> resList = new ArrayList<>();
        // 日期
        List<String> strings = getRow().get(0);
        // 日期+流程
        List<String> strings1 = getRow().get(1);
        // 表头占了5行(从0开始, 0-4)
        int count = 5;

        for (Map.Entry<Long, List<AttendanceCheckInRecord>> longListEntry : parse.stream().collect(Collectors.groupingBy(AttendanceCheckInRecord::getJobNumber)).entrySet()) {
            List<AttendanceCheckInRecord> value = longListEntry.getValue();
            Long key = longListEntry.getKey();
            // 每个员工循环5行数据
            for (int whileCount = 1; whileCount <= 5; whileCount++) {
                count++;
                List<String> str = new ArrayList<>();
                if (1 == whileCount) {
                    for (String string : strings) {
                        if ("6".equals(string)) {
                            str.add("工号");
                        } else if ("7".equals(string)) {
                            str.add(key.toString());
                        } else if ("10".equals(string)) {
                            str.add("姓名");
                        } else if ("11".equals(string)) {
                            str.add(value.get(0).getName());
                        } else {
                            str.add("");
                        }
                    }
                } else if (2 == whileCount) {
                    str.addAll(strings);
                    fontColor.add(count);
                } else if (3 == whileCount) {
                    str.addAll(strings1);
                    countList.add(count);
                } else if (4 == whileCount) {
                    randomCountList.add(count);
                    Map<String, List<AttendanceCheckInRecord>> collectByTime = value.stream().collect(Collectors.groupingBy(item -> String.valueOf(item.getPreDutyDate().getDayOfMonth())));
                    for (String string : strings) {
                        if (collectByTime.containsKey(string)) {
                            StringBuilder stringBuilder = new StringBuilder();
                            List<AttendanceCheckInRecord> attendanceCheckInRecords = collectByTime.get(string);
                            for (int collectByTimeFor = 0; collectByTimeFor < attendanceCheckInRecords.size(); collectByTimeFor++) {
                                stringBuilder.append(attendanceCheckInRecords.get(collectByTimeFor).getPreDutyTime().toLocalTime().toString());
                                if (collectByTimeFor != attendanceCheckInRecords.size() - 1) {
                                    stringBuilder.append("\n");
                                }
                            }
                            str.add(stringBuilder.toString());
                        } else {
                            str.add("");
                        }
                    }
                } else {
                    str.add("+1");
                }
                resList.add(str);
            }
        }
        return resList;
    }

    private List<List<String>> getRow() {
        List<List<String>> rows = new ArrayList<>();
        List<String> row1 = new ArrayList<>();

        List<LocalDate> ascDateList = LocalDateUtil.getTimeHorizonList(LocalDate.of(2025, 4, 1), LocalDate.of(2025, 4, 30));
        ascDateList.forEach(a -> {
            int dayOfMonth = a.getDayOfMonth();
            row1.add(String.valueOf(dayOfMonth));
        });

        List<String> row2 = new ArrayList<>();

        ascDateList.forEach(a -> {
            int value = a.getDayOfWeek().getValue();
            if (1 == value) {
                row2.add("一");
            } else if (2 == value) {
                row2.add("二");
            } else if (3 == value) {
                row2.add("三");
            } else if (4 == value) {
                row2.add("四");
            } else if (5 == value) {
                row2.add("五");
            } else if (6 == value) {
                row2.add("六");
            } else if (7 == value) {
                row2.add("日");
            } else {
                row2.add("");
            }
        });
        //加班	调休	剩余调休	请假类型：1-年假；2-事假；3-病假；4-婚假；5-产假；6-陪产假；7-丧假；8-调休；9-其他
        row2.add("");
        //迟到	早退	缺卡
        row2.add("迟到(次)");
        row2.add("早退(次)");
        row2.add("缺卡(次)");

        row2.add("矿工(次)");
        row2.add("加班(h)");
        row2.add("调休(h)");
        row2.add("剩余调休(h)");
        row2.add("剩余年假(h)");
        row2.add("出差(h)");
        row2.add("年假(h)");
        row2.add("事假(h)");
        row2.add("病假(h)");
        row2.add("婚假(h)");
        row2.add("产假(h)");
        row2.add("陪产假(h)");
        row2.add("丧假(h)");
        row2.add("其他(h)");

        rows.add(row1);
        rows.add(row2);
        return rows;
    }

    private List<List<String>> getHead() {
        List<List<String>> resList = new ArrayList<>();
        List<String> head = new ArrayList<>();
        head.add("考勤汇总 统计日期" + LocalDate.of(2025, 4, 1) + "至" +  LocalDate.of(2025, 4, 30));
        head.add("");
        head.add("");
        head.add("");
        head.add("");
        head.add("报表生成时间：" + LocalDateTime.now().withNano(0).toString().replace("T", " "));
        resList.add(head);
        return resList;
    }
}
